package com.diaohw.platform.common.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.std.DateSerializer;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
import java.util.TimeZone;

public class JacksonUtil {


    /**
     * jackson 序列化配置
     */
    public static ObjectMapper createObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 设置时区
        objectMapper.setTimeZone(TimeZone.getTimeZone(getTimeZone()));
        // 以属性字段为单位序列化，get/set 方法不进行序列化
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
        objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        // 值为空时不进行序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, Boolean.TRUE);
        objectMapper.configure(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL, Boolean.TRUE);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, Boolean.FALSE);

        objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, Boolean.TRUE);
        objectMapper.disable(DeserializationFeature.READ_ENUMS_USING_TO_STRING,
                DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE);


        objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, JsonGenerator.Feature.IGNORE_UNKNOWN);

        //注册模块
        objectMapper.registerModule(javaTimeModule())
                .registerModule(new Jdk8Module())
                .registerModule(new ParameterNamesModule())

        ;

        return objectMapper;
    }


    public static JavaTimeModule javaTimeModule() {
        JavaTimeModule javaTimeModule = new JavaTimeModule();

        // 序列化配置,针对java8 时间
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DatePattern.createFormatter(getDateFormat())));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DatePattern.NORM_DATE_FORMATTER));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DatePattern.NORM_TIME_FORMATTER));
        javaTimeModule.addSerializer(Date.class, new DateSerializer());

        //反序列化配置,针对java 时间
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer());
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer());
        javaTimeModule.addDeserializer(Date.class, new DateDeserializer());
        return javaTimeModule;
    }


    public static String getDateFormat() {
        String property = SpringUtil.getProperty("spring.jackson.date-format");
        if (StrUtil.isBlank(property)) {
            return DatePattern.NORM_DATETIME_MS_PATTERN;
        }
        return property;
    }

    public static String getTimeZone() {
        String property = SpringUtil.getProperty("spring.jackson.time-zone");
        if (StrUtil.isBlank(property)) {
            return "GMT+8";
        }
        return property;
    }

    /**
     * 日期时间反序列化处理
     */
    public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
        @Override
        public LocalDateTime deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
            return Convert.toLocalDateTime(parser.getText());
        }
    }

    /**
     * 日期反序列化处理
     */
    public static class LocalDateDeserializer extends JsonDeserializer<LocalDate> {
        @Override
        public LocalDate deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
            return Convert.toLocalDateTime(parser.getText()).toLocalDate();
        }
    }

    /**
     * 时间反序列化处理
     */
    public static class LocalTimeDeserializer extends JsonDeserializer<LocalTime> {
        @Override
        public LocalTime deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
            return Convert.toLocalDateTime(parser.getText()).toLocalTime();
        }
    }

    /**
     * 日期反序列化处理
     */
    public static class DateDeserializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
            return Convert.toDate(parser.getText());
        }
    }

}
